概览
文本生成应用是 Dify 中最简单的一种应用。但是流程和其他应用(聊天助手,Agent)差不多。所以做为入门了解整个问答流程,是非常不错的选择。
文本生成应用
功能描述
文本生成应用支持以下功能:
功能名称 | 功能含义 |
---|---|
前缀提示词 | 提示词用于对AI的回复做出一系列指令和约束。可插入表单变量例如{input}。这段提示词不会被最终用户所看到。 |
变量 | 变量将以表单形式让用户在对话前填写,用户填写的表单内容将自动替换提示词中的变量 |
上下文 | 支持添加知识库做为上下文信息,且支持两种召回方式。N选1召回和多路召回。 |
更多类似 | 一次生成多条文本,可在此基础上编辑并继续生成 |
文字转语音 | 启用后,文本可以转换成语音 |
内容审查 | 您可以调用审查 API 或者维护敏感词库来使模型更安全地输出。支持 OpenAI Moderation,关键词,API 拓展三种方式 |
接口信息
调用 /console/api/apps/xxx/completion-messages
接口。调用 AppGenerateService.generate 方法,app_model.mode 是 ‘completion’。
流程详解
- 文本生成应用,因为没有会话的概念,所以和其他类型的 APP 不一样,这里就没有 conversation,conversation 为 None
- 然后根据 app_model 和 conversation 获取 app model config, 如果是 debug 模式,则允许用户传递的 model config 覆盖 app model config
- 解析文件得到 file_objs
- 转换为 app config
- 初始化 application generate entity
- 初始化 generate records。得到一个 conversation 和 message 对象
- 初始化 queue manager
- 启动线程,调用 _generate_worker 方法
- 判断 token 数量是否足够。加载模型实例,获取模型的最大 token 数,将用户自定义的变量和问题组合成为一个 prompt,然后计算 prompt 的需要的 token 数,最后计算 token 是否足够,不足够则返回异常
- 重新组织 prompt message
- 敏感词检测
- 填写来自外部数据工具的变量输入,获取上下文信息
- 再次重新组织 prompt message
- 再次敏感词检测
- 重新判断 token 数量是否足够
- 初始化模型实例,调用大模型
- 得到 response,将 response 转换后返回出去
在 dify 中,问答的逻辑都是在线程中处理的,线程中的结果通过内存消息队列进行传输。也就是说,在线程中进行与大模型等各种的交互,交互的结果通过队列传输到线程外。所以在第 7 步的内容是初始化了一个队列,消息队列的基本操作如下:
1 | class AppQueueManager: |
敏感词检测是通过用户不同的选择(前端界面)来进行的。主要逻辑为实例化 ModerationFactory,然后调用 moderation_for_inputs 方法。如果匹配到敏感词,就不会继续下面的流程了。
1 | moderation_factory = ModerationFactory(...) |
从知识库中获取上下文,也是整个环节中比较重要的一部分,并且支持不同的召回方式(N选1召回和多路召回),有因为不同的模型所支持的功能不一样,所以这里的实现也有所区别。
N选1召回:
- 如果大模型支持 FunctionCall,且作为上下文的知识库的数量大于1,那么就会让大模型来进行选择。大模型返回被调用的 function 名称
- 如果大模型不支持 FunctionCall,且作为上下文的知识库的数量大于1,那么就使用 ReAct 的方法
多路召回:
- 多路召回则直接启用多线程去向量数据库中查询,比如目前有三个知识库作为上下文,则启动三个线程进行相关 document 的召回。然后在使用 rerank 模型对召回的结果进行重新排序。
当上下文从知识库中查询出来后,下一步会重新组织 prompt message,将上下文信息添加到 prompt message 中去。重新计算 token 等。
总结
生成文本应用比较简单,和聊天助手相比,少了一些功能,例如:对话开场白,下一步问题建议,引用和归属,标注回复等。和 Agent 相比,也没有那么复杂,Agent 涉及 FunctionCall,CoT 等调用方式。
不过三者在调用流程上都是差不多的,其他两种应用的调用流程和本次介绍的调用流程,差不多 90% 的部分是类似的。只是细节实现和侧重点不一样而已。